package Client.rpcClient.impl;

import Client.netty.nettyInitializer.NettyClientInitializer;
import Client.rpcClient.RpcClient;
import Client.serviceCenter.ServiceCenter;
import Client.serviceCenter.ZKServiceCenter;
import common.Message.RpcRequest;
import common.Message.RpcResponse;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.AttributeKey;

import java.net.InetSocketAddress;

public class NettyRpcClient implements RpcClient {

    private ServiceCenter serviceCenter;
    private String host;
    private int port;

    // netty客户端初始化,负责设置与服务器的连接配置
    private static final Bootstrap bootstrap;
    // netty客户端线程池,用于处理客户端的I/O操作,NIO模型
    private static final EventLoopGroup eventLoopGroup;

    // 从固定端口号和地址改为zk传入
    public NettyRpcClient() throws InterruptedException {
        this.serviceCenter = new ZKServiceCenter();
    }
    public NettyRpcClient(ServiceCenter serviceCenter){
        this.serviceCenter = serviceCenter;
    }

    // netty客户端初始化
    static {
        bootstrap = new Bootstrap();
        eventLoopGroup = new NioEventLoopGroup();
        bootstrap.group(eventLoopGroup)
                // 配置客户端的channel类型: NioSocketChannel
                .channel(NioSocketChannel.class)
                // 配置netty的消息处理机制
                .handler(new NettyClientInitializer());
    }

    public NettyRpcClient(String host, int port) {
        this.host = host;
        this.port = port;
    }

    @Override
    public RpcResponse sendRequest(RpcRequest request) {
        //从注册中心获取host,post
        InetSocketAddress address = serviceCenter.serviceDiscover(request.getInterfaceName());
        String host = address.getHostName();
        int port = address.getPort();

        try {
            // 创建ChannelFuture对象，sync方法表示堵塞直到connect完成
            ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
            // channel表示1个连接单位
            Channel channel = channelFuture.channel();
            // 向服务端发送消息
            channel.writeAndFlush(request);
            // sync()堵塞直到获取结果
            channel.closeFuture().sync();
            /**
             * 阻塞获取结果，通过给channel设计别名，获取特定别名的channel的内容
             * AttributeKey 线程隔离：线程安全
             * 当前场景下选择堵塞获取结果，也可以选择添加监听器非堵塞获取结果，channelFuture.addListener(future -> {})
             */
            AttributeKey<RpcResponse> key = AttributeKey.valueOf("RPCResponse");
            RpcResponse rpcResponse = channel.attr(key).get();
            System.out.println("netty_rpcResponse = " + rpcResponse);
            return rpcResponse;

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
